package com.gilight.base.config;

import com.gilight.base.dto.JwtUser;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

public class RedisSessionDAO extends AbstractSessionDAO {

    private Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);

    private String keyPrefix = "shiro:session:";
    private String keyPrefixCAS = "online-token";

    @Value("${refreshTokenExpireTime}")
    private Integer refreshTokenExpireTime;
    @Autowired
    private RedisTemplate userRedisTemplateObject;


    private void saveSession(Session session) throws UnknownSessionException {
        if (session != null && session.getId() != null) {
            session.setTimeout(refreshTokenExpireTime*1000L);
            userRedisTemplateObject.opsForValue().set(getKeyPrefix()+session.getId(),session);
            userRedisTemplateObject.expire(getKeyPrefix()+session.getId(),refreshTokenExpireTime*1000L, TimeUnit.MILLISECONDS);
        } else {
            logger.error("session or session id is null");
            throw new UnknownSessionException("session or session id is null");
        }
    }

    @Override
    protected Serializable doCreate(Session session) {
        if (session == null) {
            logger.error("session is null");
            throw new UnknownSessionException("session is null");
        } else {
            Serializable sessionId = this.generateSessionId(session);
            this.assignSessionId(session, sessionId);
            this.saveSession(session);
            return sessionId;
        }

    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        if (sessionId == null) {
            logger.warn("session id is null");
            return null;
        } else {
            Session s =null;
            s = (Session)userRedisTemplateObject.opsForValue().get(getKeyPrefix()+sessionId);
            if(s==null){
                String token = String.valueOf(sessionId);

                if (token != null && token.startsWith("Bearer ")) {
                    token =  token.substring(7);
                }
                JwtUser jwtUser = (JwtUser)userRedisTemplateObject.opsForValue().get(getcasKeyPrefix()+token);
                SimpleSession session = new SimpleSession();
                session.setId(sessionId);
                return session;
            }
            return s;
        }
    }

    @Override
    public void update(Session session) throws UnknownSessionException {
        this.saveSession(session);
    }

    @Override
    public void delete(Session session) {
        if (session != null && session.getId() != null) {
            userRedisTemplateObject.delete(session.getId());
        } else {
            logger.error("session or session id is null");
        }
    }

    @Override
    public Collection<Session> getActiveSessions() {
        Set<Session> sessions = new HashSet<Session>();
        Set keys = userRedisTemplateObject.keys(getKeyPrefix()+"*");
        for(Object key : keys){
            Session session=(Session) userRedisTemplateObject.opsForValue().get(key);
            sessions.add(session);
        }
        return sessions;
    }

    public String getKeyPrefix() {
        return keyPrefix;
    }
    public String getcasKeyPrefix() {
        return keyPrefixCAS;
    }
    public void setKeyPrefix(String keyPrefix) {
        this.keyPrefix = keyPrefix;
    }


    public Serializable doCreate(String token, JwtUser jwtUser) {
        if (token != null) {
            userRedisTemplateObject.opsForValue().set(getcasKeyPrefix()+token,jwtUser);
            userRedisTemplateObject.expire(getcasKeyPrefix()+token,refreshTokenExpireTime*1000L, TimeUnit.MILLISECONDS);
        } else {
            logger.error("session or session id is null");
            throw new UnknownSessionException("session or session id is null");
        }
        return token;
    }
}
